summaryrefslogtreecommitdiff
path: root/app/[lng]/admin/edp/components/contract-items-edit-form.tsx
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-08-27 08:24:58 +0000
committerjoonhoekim <26rote@gmail.com>2025-08-27 08:24:58 +0000
commite2ed31dd0112dc3bede53ceef9b957d2810e141e (patch)
tree9727511febf5b51ee897b0ae2f24f6b68a95cbad /app/[lng]/admin/edp/components/contract-items-edit-form.tsx
parent026ce088c638b50f493fe9aedf36e0659cb368c3 (diff)
(김준회) 임시 관리자 페이지 - EDP 데이터 수동 관리 추가 및 세션검증 추가
Diffstat (limited to 'app/[lng]/admin/edp/components/contract-items-edit-form.tsx')
-rw-r--r--app/[lng]/admin/edp/components/contract-items-edit-form.tsx204
1 files changed, 204 insertions, 0 deletions
diff --git a/app/[lng]/admin/edp/components/contract-items-edit-form.tsx b/app/[lng]/admin/edp/components/contract-items-edit-form.tsx
new file mode 100644
index 00000000..18fe75de
--- /dev/null
+++ b/app/[lng]/admin/edp/components/contract-items-edit-form.tsx
@@ -0,0 +1,204 @@
+'use client'
+
+import { useState, useEffect } from 'react'
+import { Button } from '@/components/ui/button'
+
+import { Label } from '@/components/ui/label'
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
+import { Badge } from '@/components/ui/badge'
+import { toast } from 'sonner'
+import { deleteContractItem } from '../actions/contract-actions'
+import { getContractItems } from '../actions/data-actions'
+import { ContractSelector } from './contract-selector'
+import { Trash2 } from 'lucide-react'
+
+interface Contract {
+ id: number
+ contractNo: string
+ contractName: string
+ status: string
+ projectId: number
+ vendorId: number
+ projectCode: string | null
+ projectName: string | null
+ vendorName: string | null
+ vendorCode: string | null
+}
+
+interface ContractItem {
+ id: number
+ contractId: number
+ itemId: number
+ description: string | null
+ quantity: number
+ unitPrice: number | null
+ ProjectNo: string | null
+ itemCode: string | null
+ itemName: string | null
+ packageCode: string | null
+ unitOfMeasure: string | null
+}
+
+interface ContractItemsEditFormProps {
+ preselectedContractId?: number
+}
+
+export function ContractItemsEditForm({ preselectedContractId }: ContractItemsEditFormProps) {
+ const [loading, setLoading] = useState(false)
+ const [selectedContract, setSelectedContract] = useState<Contract | undefined>()
+ const [contractItems, setContractItems] = useState<ContractItem[]>([])
+
+ // 계약 선택 시 아이템들 로드
+ useEffect(() => {
+ if (selectedContract) {
+ loadContractItems(selectedContract.id)
+ }
+ }, [selectedContract])
+
+ const loadContractItems = async (contractId: number) => {
+ setLoading(true)
+ try {
+ const result = await getContractItems(contractId)
+ if (result.success) {
+ setContractItems(result.data)
+ } else {
+ toast.error(result.error)
+ }
+ } catch (error) {
+ toast.error('계약 아이템을 불러오는 중 오류가 발생했습니다.')
+ } finally {
+ setLoading(false)
+ }
+ }
+
+
+
+ const handleDelete = async (itemId: number) => {
+ if (!confirm('정말로 이 계약 아이템을 삭제하시겠습니까?')) {
+ return
+ }
+
+ setLoading(true)
+ try {
+ const result = await deleteContractItem(itemId)
+
+ if (result.success) {
+ toast.success(result.message)
+ // 아이템 목록 새로고침
+ if (selectedContract) {
+ await loadContractItems(selectedContract.id)
+ }
+ } else {
+ toast.error(result.error)
+ }
+ } catch (error) {
+ toast.error('계약 아이템 삭제 중 오류가 발생했습니다.')
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ return (
+ <Card>
+ <CardHeader>
+ <CardTitle>계약 아이템 삭제</CardTitle>
+ <CardDescription>
+ 기존 계약의 아이템들을 삭제할 수 있습니다.
+ </CardDescription>
+ </CardHeader>
+ <CardContent>
+ <div className="space-y-6">
+ {/* 계약 선택 */}
+ <div>
+ <Label>계약 선택 *</Label>
+ <ContractSelector
+ selectedContract={selectedContract}
+ onContractSelect={setSelectedContract}
+ disabled={loading}
+ preselectedContractId={preselectedContractId}
+ />
+ </div>
+
+ {selectedContract && (
+ <div className="bg-muted/50 p-3 rounded-md">
+ <div className="text-sm font-medium">선택된 계약</div>
+ <div className="text-sm text-muted-foreground">
+ [{selectedContract.contractNo}] {selectedContract.contractName}
+ </div>
+ </div>
+ )}
+
+ {/* 계약 아이템 목록 */}
+ {contractItems.length > 0 && (
+ <div>
+ <Label>계약 아이템 목록 ({contractItems.length}개)</Label>
+ <div className="mt-2 space-y-3 max-h-96 overflow-y-auto border rounded-md p-3">
+ {contractItems.map(item => (
+ <div key={item.id} className="p-3 bg-white border rounded-md">
+ <div className="flex items-start justify-between">
+ <div className="flex-1">
+ <div className="flex items-center gap-2 mb-2">
+ <span className="font-medium">{item.itemName || `아이템 ${item.itemId}`}</span>
+ {item.itemCode && (
+ <Badge variant="outline" className="text-xs">
+ {item.itemCode}
+ </Badge>
+ )}
+ {item.unitOfMeasure && (
+ <Badge variant="secondary" className="text-xs">
+ {item.unitOfMeasure}
+ </Badge>
+ )}
+ </div>
+
+ {item.ProjectNo && (
+ <div className="text-xs text-muted-foreground mb-1">
+ 프로젝트: {item.ProjectNo} | 패키지: {item.packageCode}
+ </div>
+ )}
+
+ {/* 보기 모드만 유지 */}
+ <div className="text-sm space-y-1">
+ <div>수량: {item.quantity} | 단가: {item.unitPrice || 0}</div>
+ {item.description && (
+ <div className="text-muted-foreground">설명: {item.description}</div>
+ )}
+ </div>
+ </div>
+
+ {/* 삭제 버튼만 유지 */}
+ <div className="flex gap-1 ml-2">
+ <Button
+ type="button"
+ variant="ghost"
+ size="sm"
+ onClick={() => handleDelete(item.id)}
+ disabled={loading}
+ className="text-red-600 hover:text-red-700"
+ >
+ <Trash2 className="h-4 w-4" />
+ </Button>
+ </div>
+ </div>
+ </div>
+ ))}
+ </div>
+ </div>
+ )}
+
+ {selectedContract && contractItems.length === 0 && !loading && (
+ <div className="text-center py-8 text-muted-foreground">
+ 선택된 계약에 아이템이 없습니다.
+ </div>
+ )}
+
+ {loading && (
+ <div className="text-center py-8 text-muted-foreground">
+ 로딩 중...
+ </div>
+ )}
+ </div>
+ </CardContent>
+ </Card>
+ )
+}